//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
namespace Microsoft.Research.eResearch.Executor
{
    using System;
    using Microsoft.Research.DataLayer;
    using System.Configuration;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;

    /// <summary>
    /// Excute the schedule by creating an entry in Jobs table.
    /// </summary>
    public class ScheduleExecuterApp
    {
        /// <summary>
        /// Handle to the registry.
        /// </summary>
        private static Connection registryHandle = null;

        private static int maxRetryCount = 100;
        private static int timeInterval = 5000;

        /// <summary>
        /// Gets Handle to talk to the registry.
        /// </summary>
        public static Connection RegistryHandle
        {
            get { return registryHandle; }
        }

        /// <summary>
        /// Gets or sets the schedule id.
        /// </summary>
        /// <value>The schedule id.</value>
        public static Guid ScheduleId { get; set; }

        /// <summary>
        /// Mains the specified args.
        /// </summary>
        /// <param name="args">Schedule Id in form of args.</param>
        public static void Main(string[] args)
        {
            try
            {
                Initialize();

                OpenRegistry();

                if (args.Length > 0)
                {
                    ScheduleExecuterApp.ScheduleId = new Guid(args[0]);
                }

                CreateWorkflowJob();
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
            }
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        private static void Initialize()
        {
            string retryInterval = ConfigurationManager.AppSettings["RegistryRetryInterval"];
            if (!string.IsNullOrEmpty(retryInterval))
            {
                if (!int.TryParse(retryInterval, out timeInterval))
                {
                    // By Default the timeinterval is set to 5 seconds.
                    timeInterval = 5000;
                }
            }

            string attempts = ConfigurationManager.AppSettings["RegistryRetryCount"];
            if (!string.IsNullOrEmpty(attempts))
            {
                if (!int.TryParse(attempts, out maxRetryCount))
                {
                    // By default the retry interval is set to 100.
                    maxRetryCount = 100;
                }
            }
        }

        /// <summary>
        /// Creates the workflow job in the registry.
        /// </summary>
        /// <returns>Created JobID.</returns>
        private static Guid CreateWorkflowJob()
        {
            try
            {
                JobSchedule schedule = JobSchedule.Load(ScheduleExecuterApp.ScheduleId, ScheduleExecuterApp.RegistryHandle);
                Job jobTemplate = schedule.Template;

                // Create a new job for this job tempelate.
                Job.CopyHelper copyHelper = new Job.CopyHelper(jobTemplate.ScheduledBy);
                Job jobToExecute = jobTemplate.CopyTo(ScheduleExecuterApp.RegistryHandle, copyHelper) as Job;
                jobToExecute.IsTemplate = false;
                jobToExecute.Machines.Add(schedule.Template.Machines[0]);
                jobToExecute.ActivityInstances.Add(jobTemplate.ActivityInstances[0]);

                AdditionalParameter.CopyHelper additionalParameterCopyHelper = new AdditionalParameter.CopyHelper(jobToExecute);
                foreach (AdditionalParameter additionalParameter in jobTemplate.AdditionalParameters)
                {
                    additionalParameter.CopyTo(ScheduleExecuterApp.registryHandle, additionalParameterCopyHelper);
                }

                jobToExecute.Save();
                return Guid.Empty;
            }
            catch (Exception)
            {
                return Guid.Empty;
            }
            finally
            {
                ScheduleExecuterApp.RegistryHandle.Close();
            }
        }

        /// <summary>
        /// Open the Registry from config file whihc has Default Connection Set.
        /// </summary>
        private static void OpenRegistry()
        {
            ConnectionManager mgr = null;
            bool isValid = true;
            int errorCount = 0;

            SR_Connection.Init();
            mgr = ConnectionManager.CreateForAgent(
                             ConnectionManager.CancelBehavior.ThrowException,
                             ConnectionManager.Agent.ExecutionService);

            do
            {
                try
                {
                    registryHandle = mgr.PickConnection(ConnectionManager.ConnectionUI.NeverShowUI);
                    registryHandle.AutoSave = false;
                    registryHandle.Open();
                    isValid = true;
                }
                catch (Microsoft.Research.DataLayer.ConnectionFailure connFailure)
                {
                    Console.WriteLine(connFailure.Message);
                    isValid = !(++errorCount <= maxRetryCount);
                    System.Threading.Thread.Sleep(timeInterval);
                }
                catch (InvalidOperationException invalidException)
                {
                    Console.WriteLine(invalidException.Message);
                    isValid = !(++errorCount <= maxRetryCount);
                    System.Threading.Thread.Sleep(timeInterval);
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.Message);
                    isValid = !(++errorCount <= maxRetryCount);
                    System.Threading.Thread.Sleep(timeInterval);
                }
            } while (!isValid);

            if (null == registryHandle)
            {
                if (errorCount >= maxRetryCount)
                {
                    Console.WriteLine(TridentCommonResourceManager.GetString("RegistryNotValid"));
                }
                else
                {
                    Console.WriteLine(TridentCommonResourceManager.GetString("RegistryNotSelected"));
                }

                Environment.Exit(0);
            }
        }
    }
}
